//Helena F. Deus, 5/7/2010
//draw a sparql canvas interface
//dependencies
if(!self.get) include('get.js', 's3db');
if(!self.s3dbcall) include('s3dbcall.js', 's3dbcall');
if(!self.S3QLtranslator) include('s3ql_translator.js','s3db');

if(!self.s3db) include('basic.js', 's3db');
include('http://s3db.mathbiol-lena.googlecode.com/hg/s3db.core.js');
//include('http://canvas-text.googlecode.com/svn/trunk/canvas.text.js');
//include('http://canvas-text.googlecode.com/svn/trunk/faces/optimer-normal-normal.js');
include('movable_obj.js');
include('textcanvas3.js');
include('graphit.js');
//include('elements.js');
var cache = [];
var separation;
var availableHeight;
var availableWidth;
$(document).ready(function(){
  
   //outline the display: 50% for central canvas, 16.6% for all others
	//Lefter div will take the s3db collection for dragging
	
	availableHeight = $(window).height();
	availableWidth = $(window).width();
	separation = 10;
	
	var elements = {
			'panel1': 
				{
				'element':'div', 'id': 'panel1', 'style': 'position: absolute; background-color: #246BB3; border-color: #FFCC66 ; border-width: 2px; border-style: dashed; width: '+(availableWidth*0.5/3)+'; height: '+availableHeight
				},
			
			'midCanvas': 
				{
				'element':'div', 'id': 'midCanvas', 'style': 'position: absolute;  left: '+(availableWidth*0.5/3)+' ;width: '+(availableWidth*0.5)+'; height: '+availableHeight
				},
			
			'panel2' :
				{
				'element':'div', 'id': 'panel2', 'style': 'position: absolute; background-color: #246BB3;  border-color: #FFCC66 ; border-width: 2px; border-style: dashed;left: '+(availableWidth*0.5+availableWidth*0.5/3)+'; width: '+(availableWidth*0.5/3)+'; height: '+availableHeight
				},
			'panel3' :
				{
				'element':'div', 
				'id': 'panel3', 
				'style': 'position: absolute; background-color: #246BB3; border-color: #FFCC66 ; border-width: 2px; border-style: dashed; left: '+(availableWidth*0.5+availableWidth*0.5/3*2+separation)+'; width: '+(availableWidth*0.5/3)+'; height: '+availableHeight
				},
			//a logo that can be hovered to obtain usage information
			'logo' : 
				{
				'element' : 'canvas',
				'id' : 'logo',
				'style' : 'position: absolute;  left: '+(availableWidth*0.5/3+availableWidth*0.5/2-320/2)+'; top: -20px; background-image: url(sparql4s3db.png); width: 320px; height: 147px; background-repeat:no-repeat'
								
				},
			'CollectionCanvas'  : function (data){
					
					this.element = 'div', 
					this.attr = {'title': data.label+((data.info.notes!='')?':'+data.info.notes:'') }, 
					this.id = (typeof(data.id)!=='undefined') ? data.id : 'id',
					this.label = (typeof(data.label)!=='undefined') ? data.label : 'label',
					this.height = (typeof(data.height)!=='undefined') ? data.height : 70,
					this.width = (typeof(data.width)!=='undefined') ? data.width : ((availableWidth*0.5/3)*0.8),
					this.top = (typeof(data.top)!=='undefined') ? data.top : 10,
					this.left = (typeof(data.left)!=='undefined') ? data.left : 10,
					this.style = ((typeof(data.style)!=='undefined') ? data.style+'; ':'')+ 'position: absolute; width: '+((availableWidth*0.5/3)*0.8)+'px',
					this.prependTo = '#panel1',
					this.data = data.data;
					this.click = function () {
						console.log('You clicked '+this.id);
						//Only if rules are ready, clicking the collection will display the rules in panel 3 and query items; items are displayed immediatelly;
						if(cache['R|subject_id = '+data.id]){
							//this will happen if the rules of the collection have already been discovered; most of the cases will find this variable empty
							
						}
						else if(cache['R|P'+GET.project_id]){
							//note that, for speed purposes, only the project rules are immediatelly available; there may be cases when the subject rules will be necessary (for example, a cshared collections), in those cases, the algortihms is redundant and those rules will be retrieved
							var ProjRules = cache['R|P'+GET.project_id]; 
							//these caches are diff from R|sub... because they do not result from a direct query
							if(typeof(cache['C'+this.id+'_rules'])=='undefined'){
								for (var i=0; i<ProjRules.length; i++) {
									if(typeof(cache['C'+ProjRules[i].subject_id+'_rules'])=='undefined')
										{cache['C'+ProjRules[i].subject_id+'_rules'] = [];}
										cache['C'+ProjRules[i].subject_id+'_rules'].push(ProjRules[i]);
								}
							}
							//now finally display the rules for the selected collection only
							displayR(cache['C'+this.id+'_rules']);
						}
						else {
							alert('Just a few seconds... almost done loading the Rules!');
						}
					}
					this.mousedown = function () {
						grab(this);
					};
					
					this.canvasStyle = {'strokeStyle': "rgb(255, 0, 0)", 'fillStyle': "rgba(170, 255, 0, 0.1)","fontColor" : "#CCFFFF", "fontSize" : 20}
					
					
				},
			'RuleCanvas'  : function (data){
					this.element = 'div', 
					this.attr = {'title': data.info.subject+' | '+data.info.verb+' | '+data.info.object+((typeof(data.info.notes)!='undefined')?':'+data.notes:'') }, 
					this.id = (typeof(data.id)!=='undefined') ? data.id : 'id',
					this.label = (typeof(data.label)!=='undefined') ? data.label : 'label',
					this.height = (typeof(data.height)!=='undefined') ? data.height : 80,
					this.top = (typeof(data.top)!=='undefined') ? data.top : 10,
					this.left = (typeof(data.left)!=='undefined') ? data.left : 10,
					this.width = (typeof(data.width)!=='undefined') ? data.width : ((availableWidth*0.5/3)*0.8),
					this.style = ((typeof(data.style)!=='undefined') ? data.style+'; ':'')+ 'position: absolute; width: '+(availableWidth*0.5/3*0.8)+'px',
					this.prependTo = '#panel3',
					this.data = data.data;
					this.click = function () {
						console.log('You clicked '+this.id);
						
					}
					this.mousedown = function () {
						grab(this);
					};
					this.canvasStyle = {'strokeStyle': "rgb(255, 255, 46)", 'fillStyle': "rgba(255, 221, 51,0.1)","fontColor" : "black", "fontSize" : 16}
					
				}
				
		}
		

	var gets3dbquery = function (q) {
		
		var url = ((GET.url.match(/\/$/)!==-1)?GET.url: GET.url+'/')+'S3QL.php?key='+GET.key+'&query=';
		var query = S3QLtranslator(q);
		var qu = url+query+'&format=json';
		
		var type = q.match(/(P|R|C|I|S|U|G)\|/)[1]; 
		var id = s3db.core.ids[type];
		
		return qu;
	}

    var displayC = function (data){
	  var usefulData=[];j=0;
	  for (var i=0; i<data.length; i++) {
		if(data[i].name!=='s3dbVerb'){
			usefulData[j] = data[i];
			j++;
		}
	  }
	  var data = usefulData;
	  cache['C|P'+GET.project_id] = data;
	  //let us determine how much space will this ocupy
		var x = 60; var h = (separation*8); //defH is height of box; defX is the separation between the boxes
		var n = data.length;
		if((x*n+h*(n-1))>availableHeight ){
			var smallh = ((availableHeight-x*n)/(n-1));
			var h = Math.max(5, smallh);
		}
		
	 document.getElementById('panel1').innerHTML=''; 
	  $.each(data, function(i,item){
		var collectionElement = {};
		collectionElement.id = item.collection_id;
		collectionElement.label = item.name;
		collectionElement.left = (separation*2);
		collectionElement.top = ((x+h)*i);
		collectionElement.height = x;
		collectionElement.style = 'left: '+(separation*2);
		collectionElement.style += '; top: '+((x+h)*i);
		collectionElement.style += '; height: '+x+'px';
		collectionElement.info = data[i];
		//collectionElement.mousedown = "grab(this)";
		collectionElement.click = function () {
			console.log('you clicked C'+item.collection_id);	
		}
		
		//for each collection make an instance of the CollectionCanvas element;
		var instElem = new elements.CollectionCanvas(collectionElement);
		
		//Draw the movable canvas
		drawElements(instElem);
		
		//Draw the elements inside the canvas
		canvasDraw(instElem);				
		
		//canvasDraw($('#'+collectionElement.id)[0]);
	  });
	}
	
	var displayR = function (data, ind){
	  
	  //let us determine how much space will this ocupy
		var x = 40; var h = (separation*8); //defH is height of box; defX is the separation between the boxes
		if(typeof(data)!='undefined'){
			var n = data.length;
			if((x*n+h*(n-1))>availableHeight ){
				var smallh = ((availableHeight-x*n)/(n-1));
				var h = Math.max(1, smallh);
			}
		  //left position should be equal to panel3 + separation
		  var leftPos = separation;
			document.getElementById('panel3').innerHTML='';   
			$.each(data, function(i,item){
			var RuleElement = {};
			RuleElement.id = item.rule_id;
			RuleElement.label = item.object;
			RuleElement.relation = item.verb;
			RuleElement.left = leftPos;
			RuleElement.top = ((x+h)*i);
			RuleElement.height = x;
			RuleElement.style = 'left: '+leftPos;
			RuleElement.style += '; top: '+((x+h)*i);
			RuleElement.style += '; height: '+x+'px';
			RuleElement.info = data[i];
			//collectionElement.mousedown = "grab(this)";
			RuleElement.click = function () {
				console.log('you clicked C'+item.rule_id);	
			}
			
			//for each collection make an instance of the CollectionCanvas element;
			var instElem = new elements.RuleCanvas(RuleElement);
			
			//Draw the movable canvas; whatever exist in the panel must be cleared first
			drawElements(instElem);
			//Draw the elements inside the canvas
			canvasDraw(instElem);				

		  });
		}
		else {
			alert('Sorry... no rules were found :(');
		}
	}

	var drawArrow = function (box1, box2, relation) {
		$(document.createElement('div')).attr('id',box1+'-'+relation+'-'+box2).attr('class','connector '+box1+' '+box2+'').append('<label class="middle-label">'+relation+'</label>').append('<img class="connector-end" src="arrow.gif"/>').prependTo("#midCanvas");
	}

	
	//retrieve the data for the collections; need project_id, key;
	get();
	
	//draw the panels, the logo and the canvas;
	drawElements( elements, [ 'panel1', 'panel2', 'midCanvas','panel3', 'logo' ] );
	
	//Call rules and collections
	if(typeof(GET.url)=='undefined') GET.url = 'http://ibl.mdanderson.org/s3dbdemo3/';
	if(typeof(GET.key)=='undefined') GET.key = '';
	if(typeof(GET.project_id)=='undefined') GET.project_id = '1715';
	var q = gets3dbquery('C|P'+GET.project_id);
	
	//display collections immediatelly; enable display rules after collection click and ONLY if the rules are ready;
	$.getJSON(q+'&callback=?', displayC);
    
	var q1 = gets3dbquery('R|P'+GET.project_id);
	$.getJSON(q1+'&callback=?', function (data) {
		cache['R|P'+GET.project_id] = data;
	});
  
	
});

function drawElements(El, ind, clear) {
	if(typeof(El)!=='undefined'){
		var DrawElements = El;
	}
	else {
		var DrawElements = elements;
	}
	if(typeof(ind)!=='undefined' && typeof(ind)==='string' && ind!==''){
		var ind = [ind];
	}
	if((typeof(ind)=='undefined' || ind=='') && typeof(El.id)!=='undefined'){
		var DrawElements = { };
		DrawElements[El.id] =  El;
		var ind = [El.id];
	}
	
	for (var i=0; i<ind.length; i++) {
		var elem_id = ind[i];
		if(typeof(DrawElements[elem_id])!=='undefined'){
			
			if(typeof(DrawElements[elem_id].prependTo)==='undefined') var prependWhere = "body";
			else {
				var prependWhere = $(DrawElements[elem_id].prependTo);
			}
			if(typeof(DrawElements[elem_id].element)=='undefined') DrawElements[elem_id].element = 'div';
			
			//clear the panel before appending
			if(typeof(clear)!=='undefined' && clear && prependWhere!=="body"){
				prependWhere.innerHTML = "";
			}
			
			var a = $(document.createElement(DrawElements[elem_id].element)).attr("id", elem_id).attr("style", DrawElements[elem_id].style).prependTo(prependWhere); 

			//also for each attribuet annotated, append it to the element
			if(typeof(DrawElements[elem_id].attr)=='object')
			for (var i in DrawElements[elem_id].attr) {
			
				a.attr(i, DrawElements[elem_id].attr[i]);
			}
			
			if(DrawElements[elem_id].click) {
				a.click(DrawElements[elem_id].click);
			}
			if(DrawElements[elem_id].mousedown) {
				a.mousedown(DrawElements[elem_id].mousedown);
			}
			
		}
	}
}


function canvasDraw(CanvasObject) {
	//the idea is to first create an invisible canvas, because this element is movable and then add the drawings to it
	if(typeof(CanvasObject)==='string')	
	 {var element = elements[CanvasObject]; }
	else {var element = CanvasObject;}
	
	var CanvasObject = $('#'+element.id)[0];
	
	if(element.canvasStyle) {var canvasStyle = element.canvasStyle; }
	else { var canvasStyle = {'fillStyle' : 'rgb(255, 255, 255)','strokeStyle' : 'rgb(0, 0, 0)', 'color': 'red', 'fontColor' : 'black','fontSize':18 }}
	
	//because i will need text implement the canvas as the lib requires it
	var H = element.height;
	var W = element.width;
	var T = element.top;
	var L = element.left;
	var textCanvasController = new TextCanvas(CanvasObject);
	textCanvasController.setDimensions(W, H);
	//if(window.G_vmlCanvasManager)
	//	 {G_vmlCanvasManager.initElement(canvas);}
	var ctx = textCanvasController.getContext('2d');
	
	//grid(ctx, W, H);
	ctx.roundedRect = function (text) {
		//a is the upper left corner, b the upper right corner c is the lower right corner, d is the lower left corner
		ang = 10;edge = 5;
		ax = 0+edge; ay = 0+edge;
		bx = (W-edge); by=0+edge;
		//somehow it is hiding the bottom line if full H is used; H-10 is a heuristic that seemed to work
		cx = (W-edge); cy = (H-10+edge);
		dx = (0+edge); dy = (H-10+edge);

		
		
		ctx.strokeStyle = canvasStyle.strokeStyle;
		ctx.lineWidth = edge;
		ctx.fillStyle = canvasStyle.fillStyle;
		ctx.beginPath();
		ctx.moveTo(ax+ang, ay);
		ctx.lineTo(bx-ang, by);
		ctx.bezierCurveTo(bx, by, bx, by,bx, by+ang); 
		ctx.lineTo(cx, cy-ang);
		ctx.bezierCurveTo(cx, cy, cx, cy,cx-ang, cy); 
		ctx.lineTo(dx+ang, dy);
		ctx.bezierCurveTo(dx, dy, dx, dy,dx, dy-ang); 
		ctx.lineTo(ax, ay+ang);
		ctx.bezierCurveTo(ax, ay, ax, ay, ax+ang, ay); 
		ctx.stroke();
		ctx.fill();
		
		if(typeof(text)!=='undefined'){
			//Measure the pixels width of the text
			var fontSize = canvasStyle.fontSize;
			var textColor = canvasStyle.fontColor;
			var strPxLeng = text.visualLength('font-size: '+fontSize);
			var Pyfactor = 1;var Pxfactor = 1;
			while(strPxLeng>=W && fontSize>12){
				//console.log(text+' must be cut');
				//match spaces, use them to break the string
				var spaces = text.match(/\s[^\s]*$/g);
				
				if(typeof(spaces)!='undefined' && spaces[0]!=''){
					var line1 = text.replace(/\s[^\s]*$/g, '');
					var line2 = '  '+spaces[0].trim();
					var text = line1+'<BR>'+line2;
					//Py will also go a bit up
					var Pyfactor = 1/2;

					//Px will be based on the larger line
					var Line1Leng = line1.visualLength('font-size: '+fontSize);
					var Line2Leng = line2.visualLength('font-size: '+fontSize);
					var strPxLeng = Math.max(Line1Leng, Line2Leng);
				}
				else {
					var fontSize = fontSize-2;
					//var text = text.substring(0, 20)+'.';
					var strPxLeng = text.visualLength('font-size: '+fontSize);
				}

			}
			
			//P is the point where string should begin; to obtain it, must subtract (box length -  strPxLength)/2 + a, where a is the start of the box
			
			var Py = (H-fontSize)/2*Pyfactor;
			var Px = (W-strPxLeng)/2*Pxfactor;			
			ctx.stringStyle.color = textColor;
			ctx.stringStyle.fontSize = fontSize;
			//ctx.drawString((W/2-(text.length*9)/2), (H/2-12), text);
			ctx.drawString(Px, Py, text);
		}

		
	}

	ctx.roundedRect(element.label);
	  
}



function include(src, path) {
	if(typeof(path)!=='undefined')
	{
		var pathTranslate = {'s3db' : 'http://s3db.mathbiol-lena.googlecode.com/hg/',
					'compstats': 'http://compstats.mathbiol-lena.googlecode.com/hg/',
					's3dbcall' : 'http://s3dbcall.googlecode.com/hg/'
					}
		var fullSrc = pathTranslate[path]+'/'+src;
	}
	else {
		var fullSrc = src;
	}
	

	try {
		document.write("<script type='text/javascript' src='"+fullSrc+"'</script>");
	}
	catch (err) {
		var fullSrc = path+'/'+src;
		document.write("<script type='text/javascript' src='"+fullSrc+"'</script>");
	}


}

function grid (ctx, width, height) {
	height = 300;
	width = 300;
	//ctx.strokeStyle = "rgba(0, 0, 200, 0.5)";
	for (var i=0; i<=width; i=i+10) {
	ctx.beginPath();
	ctx.moveTo(i,0);//all grid lines start at zero
	ctx.lineTo(i,height);
	ctx.stroke();
	}

	for (var i=0; i<=height; i=i+10) {
	ctx.beginPath();
	ctx.moveTo(0,i);//all grid lines start at zero
	ctx.lineTo(height, i);
	ctx.stroke();
	}
}